home *** CD-ROM | disk | FTP | other *** search
/ World of Education / World of Education.iso / world_r / romancvt.zip / ARAB2ROM.C next >
C/C++ Source or Header  |  1993-04-14  |  6KB  |  197 lines

  1. /* arab2rom.c
  2.  
  3.    David S McMeans     Not copyrighted April 1993
  4.    mcmeans@dtedi.hq.aflc.af.mil
  5.  
  6. Arabic2Roman()
  7. Converts an Arabic integer to its Roman equivalent.
  8.  
  9. Call
  10.  
  11. char *Arabic2Roman( num, buf )
  12. unsigned long int num;              integer to convert
  13. char *buf;                          buffer in which conversion is returned
  14.  
  15. Returns
  16.  
  17. NULL                  if num is out of range 0 to 3,999,999.
  18.  
  19. POINTER               otherwise
  20.  
  21. Description
  22.  
  23. The Romans had no concept of fractions, so all their numbers were integers.
  24. At the time their system was created, one thousand was as large a number as
  25. could be conceived and thus was given the letter M for magna (large).  A
  26. later modification extended the system a thousand fold.  Any numeral with a
  27. bar over it was defined as one thousand times its normal value.  Since it is
  28. not possible to write a character with an over-bar in ASCII, these numerals
  29. are written with an underscore to their right ( M_ = 1000 * 1000 ).
  30.  
  31.   I     1     
  32.   V     5            V_      5,000  
  33.   X    10            X_     10,000
  34.   L    50            L_     50,000      
  35.   C   100            C_    100,000
  36.   D   500            D_    500,000
  37.   M  1000            M_  1,000,000
  38.  
  39. When a number has multiple forms, it's canonical form is the shorter.  Nine
  40. is written IX, not VIIII, and ninety is XC, not LXXXX.  But, a numeral is
  41. not allowed to modify another that is more than one maginitude greater.
  42. The correct representation of 1990 is not MXM (1000 + 1000-10).  Rather, it
  43. is MCMXC (1000 + 1000-100 + 100-10).  When writing 1990, you first write
  44. the representation for 1000, then for 900, and then for 90.  You do not write
  45. down the numerals for 1000 and then for 990.  The technique is to integrally
  46. divide the number by its greatest magnitude and write down the Roman 
  47. representation for each result.  For 1989, the greatest magnitude is 1000.
  48. You would write down M.  Divide by 1000, and the result is 989.  Here the
  49. largest magnitude is 900.  Write down CM (1000-100).  Strip off the 900, and
  50. get 89.  Now the greatest magnitude is 80.  Write down LXXX.  This leaves 9
  51. which would be written as IX.
  52.  
  53. This system follows a peculiar pattern of addtion and subraction to generate
  54. the values one through 10.  Smaller numerals to the left of a larger are
  55. subracted from the larger, and smaller numerals placed to the right are added.
  56.  
  57.   1  I      11  XI      40  XL
  58.   2  II     12  XII
  59.   3  III    13  XIII    50  L
  60.   4  IV     14  IVX
  61.   5  V      15  XV      90  XC
  62.   6  VI     16  XVI
  63.   7  VII    17  XVII   100  C
  64.   8  VIII   18  XVIII
  65.   9  IX     19  XIX
  66.  10  X      20  XX
  67.  
  68. Note that 8, VIII, could be written more succinctly IIX (10-2).  I expect,
  69. only one numeral may be placed in a subtraction position.
  70.  
  71. The following constant strings are redefinable by the user.  This allows one 
  72. to substitute different characters for over-bar numerals.
  73.  
  74.   Roman_1       = "i";        Roman_5000    = "v_";
  75.   Roman_5       = "v";        Roman_10000   = "x_";
  76.   Roman_10      = "x";        Roman_50000   = "l_";
  77.   Roman_50      = "l";        Roman_100000  = "c_";
  78.   Roman_100     = "c";        Roman_500000  = "d_";
  79.   Roman_500     = "d";        Roman_1000000 = "m_";
  80.   Roman_1000    = "m";
  81.  
  82. To represent numbers four million and greater, a numeral for five million is
  83. needed.  Since no numerals exist above one million (though they could easily
  84. be fabricated), Arabic2Roman() converts integers only in the range 0 to
  85. 3,999,999.
  86.  
  87. Notes
  88.  
  89. This was compiled from a discussion in comp.lang.pascal around March 1993.
  90. Acknowledgements go to John J Cupak Jr, CPP (cupak@rapnet.sanders.lockheed.com),
  91. Paul Robinson (tdarcos@access.digex.com), and
  92. David Conrad (dave@tygra.michigan.com) for their informative articles,
  93. Prof Timo Salmi (ts@uwasa.fi) for steering me in the direction of the
  94. discussion, and to Arlin B Collins (bcollins@utdallas.edu) for sending me his
  95. collection of the articles from the discussion.
  96.  
  97. Arabic2Roman() is a modified version of the Turbo Pascal function Roman in
  98. tools.pas which is in garbo.uwasa.fi:/pc/turbopas/drcpas10.zip
  99.  
  100. */
  101.  
  102.  
  103. #include "tailor.h"
  104.  
  105. #include <stdio.h>
  106. #include <stdlib.h>
  107. #include <string.h>
  108.  
  109. #define ulong unsigned long int
  110.  
  111. /* The following constants determine the representation of each Roman
  112.    numeral, and may be redefined by the user
  113. */
  114.  
  115. char *Roman_1       = "i";
  116. char *Roman_5       = "v";
  117. char *Roman_10      = "x";
  118. char *Roman_50      = "l";
  119. char *Roman_100     = "c";
  120. char *Roman_500     = "d";
  121. char *Roman_1000    = "m";
  122. char *Roman_5000    = "v_";
  123. char *Roman_10000   = "x_";
  124. char *Roman_50000   = "l_";
  125. char *Roman_100000  = "c_";
  126. char *Roman_500000  = "d_";
  127. char *Roman_1000000 = "m_";
  128.  
  129. /*
  130.  *    PUBLIC DECLARATIONS
  131.  */
  132.  
  133. extern  char *Arabic2Roman  OF(( ulong, char * ));
  134.  
  135. /*
  136.  *    PRIVATE DECLARATIONS
  137.  */
  138.  
  139. static void roman_digit  OF(( char *, char *, char *, ulong, char * ));
  140.  
  141. char *Arabic2Roman( num, buf )
  142. ulong num;
  143. char *buf;
  144. {
  145.   strcpy( buf, "" );
  146.  
  147.   if (num > 3999999)
  148.     return NULL;
  149.  
  150.   roman_digit( Roman_1000000, " ",         " ",          num/1000000, buf );
  151.   num %= 1000000;
  152.   roman_digit( Roman_100000, Roman_500000, Roman_1000000, num/100000, buf );
  153.   num %= 100000;
  154.   roman_digit( Roman_10000,  Roman_50000,  Roman_100000,  num/10000,  buf );
  155.   num %= 10000;
  156.   roman_digit( Roman_1000,   Roman_5000,   Roman_10000,   num/1000,   buf );
  157.   num %= 1000;
  158.   roman_digit( Roman_100,    Roman_500,    Roman_1000,    num/100,    buf );
  159.   num %= 100;
  160.   roman_digit( Roman_10,     Roman_50,     Roman_100,     num/10,     buf );
  161.   num %= 10;
  162.   roman_digit( Roman_1,      Roman_5,      Roman_10,      num,        buf );
  163.   
  164.   return buf;
  165. }
  166.  
  167. static void roman_digit( one, five, ten, n, buf )
  168. char *one, *five, *ten;
  169. ulong n;
  170. char *buf;
  171. {
  172.   int i;
  173.  
  174.   switch( n )
  175.   {
  176.     case 1: case 2: case 3:
  177.       for (i=0; i < n; i++)
  178.         strcat( buf, one );
  179.       break;
  180.     case 4:
  181.       strcat( buf, one );
  182.       strcat( buf, five );
  183.       break;
  184.     case 5: case 6: case 7: case 8:
  185.       strcat( buf, five );
  186.       for (i=0; i < n-5; i++)
  187.         strcat( buf, one );
  188.       break;
  189.     case 9:
  190.       strcat( buf, one );
  191.       strcat( buf, ten );
  192.       break;
  193.   }
  194. }
  195.  
  196. /* end .c */
  197.